﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Apollo.Core
{
    public class ProjectionManagerItem
    {
        public ProjectionManagerItem(string projectionString, Type basetype) {
            // check if it is an aggregate
            if (projectionString.Contains("("))
            {
                int indexOF = projectionString.IndexOf("(");
                string aggregateValue = projectionString.Substring(0, indexOF);

                foreach (string projectionAggregateValue in System.Enum.GetNames(typeof(ProjectionAggregate))) {
                    if (aggregateValue.ToLower() == projectionAggregateValue.ToLower()) {
                        this.Aggregation = (ProjectionAggregate)System.Enum.Parse(typeof(ProjectionAggregate), projectionAggregateValue);
                        break;
                    }
                }

                projectionString = projectionString.Substring(indexOF + 1, projectionString.IndexOf(")") - indexOF - 1);
            }
            else {
                this.Aggregation = ProjectionAggregate.None;
            }

            // set the base projection
            this.Projection = new Projection(projectionString, basetype);

            if (!this.Projection.IsValid)
                return;

            if (this.Projection.IsRelation)
            {
                this.DisplayProjection = this.Projection;
                while (this.DisplayProjection.IsRelation)
                    this.DisplayProjection = new Projection(
                        this.DisplayProjection.ProjectionPath + "." + this.DisplayProjection.RelationEntity.DisplayProperty
                        , this.Projection.BaseType);

                this.IdentifierProjection = this.Projection;
                while(this.IdentifierProjection.IsRelation)
                    this.IdentifierProjection = new Projection(
                        this.IdentifierProjection.ProjectionPath + "." + this.IdentifierProjection.RelationEntity.IdentifierProperty
                        , this.Projection.BaseType);

                if (this.Aggregation > 0)
                {
                    // if we have an aggregation, the DisplayProjection will be the IdentifierProjection
                    // This is an optimization!!!!
                    this.DisplayProjection = this.IdentifierProjection;
                    this.IdentifierProjection = null;
                }
            }
            else {
                // if it's not a relation, the DisplayProjection is the same
                // as the base projection
                this.DisplayProjection = this.Projection;
            }
        }

        /// <summary>
        /// Actual projection
        /// </summary>
        public Projection Projection { get; private set; }


        /// <summary>
        /// The display projection. If the actual projection is not a relation, this will be the actual projection
        /// </summary>
        public Projection DisplayProjection { get; private set; }

        /// <summary>
        /// The alias of the DisplayProjection's column
        /// </summary>
        public string DisplayProjectionAlias { get; set; }
        public int DisplayProjectionIndex { get; set; }

        
        /// <summary>
        /// The identifier projection. This will be null if the actual projection is not a relation.
        /// </summary>
        public Projection IdentifierProjection { get; private set; }
        
        /// <summary>
        /// The alias of the IdentifierProjection's column
        /// </summary>
        public string IdentifierProjectionAlias { get; set; }
        public int IdentifierProjectionIndex { get; set; }


        public ProjectionAggregate Aggregation { get; private set; }
    }

    public enum ProjectionAggregate { 
        None = 0,

        Sum = 1,
        Count = 2,
        CountDistinct = 3,
        Max = 4,
        Min = 5,
        Avg = 6,

        Date = -10,
        Month = -11,
        Quarter = -12,
        Year = -13
    }
}
